package com.ewei.web.common.mybatis.plugin;

import java.sql.Connection;
import java.util.Properties;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.RowBounds;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
 *分页插件(物理分页）
 *拦截statementHandler
 */
@Intercepts({@Signature(type=StatementHandler.class,method="prepare",args={Connection.class})})
public class PageInterceptor implements Interceptor{
	private static final Logger logger = LogManager.getLogger(PageInterceptor.class);
	private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
	private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();
	//默认要拦截的分页id(正则表达式）
	private static final String PAGER_SQL_ID = ".*Pager$";
	public Object intercept(Invocation invocation) throws Throwable {
		StatementHandler handler = (StatementHandler)invocation.getTarget();
		MetaObject metaHandler = MetaObject.forObject(handler,DEFAULT_OBJECT_FACTORY,
				DEFAULT_OBJECT_WRAPPER_FACTORY);
		RowBounds rowBounds = (RowBounds)metaHandler.getValue("delegate.rowBounds");
		//分离代理对象链，分离出最原始的目标类
		while(metaHandler.hasGetter("h")){
			Object object = metaHandler.getValue("h");
			metaHandler = MetaObject.forObject(object,
					DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY);
		}
		//分离最后一个代理对象的目标类
		while(metaHandler.hasGetter("target")){
			Object object = metaHandler.getValue("target");
			metaHandler = MetaObject.forObject(object,
					DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY);
		}
		//读取mybatis的configuration配置
		Configuration configuration =(Configuration)metaHandler.getValue("delegate.configuration");
		//读取配置的分页查询id
		String pageSqlId = null;
		if(null != configuration.getVariables()){
			pageSqlId = configuration.getVariables().getProperty("pageSqlId");
		}
		if(null==pageSqlId||"".equals(pageSqlId)){
			pageSqlId = PAGER_SQL_ID; //使用默认配置
		}
		//获得MapperStatementHandler
		MappedStatement mappedStatement = (MappedStatement)metaHandler.getValue("delegate.mappedStatement");
		//重写需要分页的sql语句,既映射接口的sql语句的id
		if(mappedStatement.getId().matches(pageSqlId)){
			BoundSql boundSql = (BoundSql)metaHandler.getValue("delegate.boundSql");
//			Object parameterObject = boundSql.getParameterObject();
			//重写sql
			String sql = boundSql.getSql();
			String pageSql = sql.trim() + " limit " + rowBounds.getOffset()+","+rowBounds.getLimit();
			//重置mybatis的内存分页
			metaHandler.setValue("delegate.boundSql.sql",pageSql);
			logger.trace(metaHandler.getValue("delegate.boundSql.sql"));
			metaHandler.setValue("delegate.rowBounds.offset",RowBounds.NO_ROW_OFFSET);
			metaHandler.setValue("delegate.rowBounds.limit", RowBounds.NO_ROW_LIMIT);	
		}
		//推进责任链
		return invocation.proceed();
	}

	public Object plugin(Object target) {
		if(target instanceof StatementHandler){
			return Plugin.wrap(target, this); //包装代理
		}
		return target;
	}

	public void setProperties(Properties arg0) {
		//no method
	}
	
}
